home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Abalone 1.4.2 / src / Rules.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-09-21  |  11.9 KB  |  486 lines  |  [TEXT/MPS ]

  1. #define RULES_C
  2. #include "Rules.h"
  3. #undef RULES_C
  4.  
  5.  
  6. #pragma segment More
  7.  
  8.  
  9. Field             _neighbour    [kFields+1] [kDirections+1] =
  10. {
  11.     {     0,  0,  0,  0,  0,  0,  0    },    /*  0 ::= not on board */
  12.     {     2,  7,  6,  0,  0,  0,  0    },    /*  1 */
  13.     {     3,  8,  7,  1,  0,  0,  0    },    /*  2 */
  14.     {     4,  9,  8,  2,  0,  0,  0    },    /*  3 */
  15.     {     5, 10,  9,  3,  0,  0,  0    },    /*  4 */
  16.     {     0, 11, 10,  4,  0,  0,  0    },    /*  5 */
  17.     {     7, 13, 12,  0,  0,  1,  0    },    /*  6 */
  18.     {     8, 14, 13,  6,  1,  2,  0    },    /*  7 */
  19.     {     9, 15, 14,  7,  2,  3,  0    },    /*  8 */
  20.     {    10, 16, 15,  8,  3,  4,  0    },    /*  9 */
  21.     {    11, 17, 16,  9,  4,  5,  0    },    /* 10 */
  22.     {     0, 18, 17, 10,  5,  0,  0    },    /* 11 */
  23.     {     13, 20, 19,  0,  0,  6,  0    },    /* 12 */
  24.     {    14, 21, 20, 12,  6,  7,  0    },    /* 13 */
  25.     {    15, 22, 21, 13,  7,  8,  0    },    /* 14 */
  26.     {    16, 23, 22, 14,  8,  9,  0    },    /* 15 */
  27.     {    17, 24, 23, 15,  9, 10,  0    },    /* 16 */
  28.     {    18, 25, 24, 16, 10, 11,  0    },    /* 17 */
  29.     {     0, 26, 25, 17, 11,  0,  0    },    /* 18 */
  30.     {    20, 28, 27,  0,  0, 12,  0    },    /* 19 */
  31.     {    21, 29, 28, 19, 12, 13,  0    },    /* 20 */
  32.     {    22, 30, 29, 20, 13, 14,  0    },    /* 21 */
  33.     {    23, 31, 30, 21, 14, 15,  0    },    /* 22 */
  34.     {    24, 32, 31, 22, 15, 16,  0    },    /* 23 */
  35.     {    25, 33, 32, 23, 16, 17,  0    },    /* 24 */
  36.     {    26, 34, 33, 24, 17, 18,  0    },    /* 25 */
  37.     {     0, 35, 34, 25, 18,  0,  0    },    /* 26 */
  38.     {    28, 36,  0,  0,  0, 19,  0    },    /* 27 */
  39.     {    29, 37, 36, 27, 19, 20,  0    },    /* 28 */
  40.     {    30, 38, 37, 28, 20, 21,  0    },    /* 29 */
  41.     {    31, 39, 38, 29, 21, 22,  0    },    /* 30 */
  42.     {    32, 40, 39, 30, 22, 23,  0    },    /* 31 */
  43.     {    33, 41, 40, 31, 23, 24,  0    },    /* 32 */
  44.     {    34, 42, 41, 32, 24, 25,  0    },    /* 33 */
  45.     {    35, 43, 42, 33, 25, 26,  0    },    /* 34 */
  46.     {     0,  0, 43, 34, 26,  0,  0    },    /* 35 */
  47.     {    37, 44,  0,  0, 27, 28,  0    },    /* 36 */
  48.     {    38, 45, 44, 36, 28, 29,  0    },    /* 37 */
  49.     {    39, 46, 45, 37, 29, 30,  0    },    /* 38 */
  50.     {    40, 47, 46, 38, 30, 31,  0    },    /* 39 */
  51.     {    41, 48, 47, 39, 31, 32,  0    },    /* 40 */
  52.     {    42, 49, 48, 40, 32, 33,  0    },    /* 41 */
  53.     {    43, 50, 49, 41, 33, 34,  0    },    /* 42 */
  54.     {     0,  0, 50, 42, 34, 35,  0    },    /* 43 */
  55.     {    45, 51,  0,  0, 36, 37,  0    },    /* 44 */
  56.     {    46, 52, 51, 44, 37, 38,  0    },    /* 45 */
  57.     {    47, 53, 52, 45, 38, 39,  0    },    /* 46 */
  58.     {    48, 54, 53, 46, 39, 40,  0    },    /* 47 */
  59.     {    49, 55, 54, 47, 40, 41,  0    },    /* 48 */
  60.     {    50, 56, 55, 48, 41, 42,  0    },    /* 49 */
  61.     {     0,  0, 56, 49, 42, 43,  0    },    /* 50 */
  62.     {    52, 57,  0,  0, 44, 45,  0    },    /* 51 */
  63.     {    53, 58, 57, 51, 45, 46,  0    },    /* 52 */
  64.     {    54, 59, 58, 52, 46, 47,  0    },    /* 53 */
  65.     {    55, 60, 59, 53, 47, 48,  0    },    /* 54 */
  66.     {    56, 61, 60, 54, 48, 49,  0    },    /* 55 */
  67.     {     0,  0, 61, 55, 49, 50,  0    },    /* 56 */
  68.     {    58,  0,  0,  0, 51, 52,  0    },    /* 57 */
  69.     {    59,  0,  0, 57, 52, 53,  0    },    /* 58 */
  70.     {    60,  0,  0, 58, 53, 54,  0    },    /* 59 */
  71.     {    61,  0,  0, 59, 54, 55,  0    },    /* 60 */
  72.     {     0,  0,  0, 60, 55, 56,  0    }    /* 61 */
  73. };
  74.  
  75. unsigned char _distance [kFields+1] [kDirections] =
  76. {
  77.     { 0, 0, 0, 0, 0, 0 },     /*  0 */
  78.     { 5, 9, 5, 1, 1, 1 },    /*  1 */
  79.     { 4, 8, 6, 2, 1, 1 },     /*  2 */
  80.     { 3, 7, 7, 3, 1, 1 },     /*  3 */
  81.     { 2, 6, 8, 4, 1, 1 },     /*  4 */
  82.     { 1, 5, 9, 5, 1, 1 },     /*  5 */
  83.     { 6, 8, 4, 1, 1, 2 },     /*  6 */
  84.     { 5, 8, 5, 2, 2, 2 },     /*  7 */
  85.     { 4, 7, 6, 3, 2, 2 },     /*  8 */
  86.     { 3, 6, 7, 4, 2, 2 },     /*  9 */
  87.     { 2, 5, 8, 5, 2, 2 },     /* 10 */
  88.     { 1, 4, 8, 6, 2, 1 },     /* 11 */
  89.     { 7, 7, 3, 1, 1, 3 },     /* 12 */
  90.     { 6, 7, 4, 2, 2, 3 },     /* 13 */
  91.     { 5, 7, 5, 3, 3, 3 },     /* 14 */
  92.     { 4, 6, 6, 4, 3, 3 },     /* 15 */
  93.     { 3, 5, 7, 5, 3, 3 },     /* 16 */
  94.     { 2, 4, 7, 6, 3, 2 },     /* 17 */
  95.     { 1, 3, 7, 7, 3, 1 },     /* 18 */
  96.     { 8, 6, 2, 1, 1, 4 },     /* 19 */
  97.     { 7, 6, 3, 2, 2, 4 },     /* 20 */
  98.     { 6, 6, 4, 3, 3, 4 },     /* 21 */
  99.     { 5, 6, 5, 4, 4, 4 },     /* 22 */
  100.     { 4, 5, 6, 5, 4, 4 },     /* 23 */
  101.     { 3, 4, 6, 6, 4, 3 },     /* 24 */
  102.     { 2, 3, 6, 7, 4, 2 },     /* 25 */
  103.     { 1, 2, 6, 8, 4, 1 },     /* 26 */
  104.     { 9, 5, 1, 1, 1, 5 },     /* 27 */
  105.     { 8, 5, 2, 2, 2, 5 },     /* 28 */
  106.     { 7, 5, 3, 3, 3, 5 },     /* 29 */
  107.     { 6, 5, 4, 4, 4, 5 },     /* 30 */
  108.     { 5, 5, 5, 5, 5, 5 },     /* 31 */
  109.     { 4, 4, 5, 6, 5, 4 },     /* 32 */
  110.     { 3, 3, 5, 7, 5, 3 },     /* 33 */
  111.     { 2, 2, 5, 8, 5, 2 },     /* 34 */
  112.     { 1, 1, 5, 9, 5, 1 },     /* 35 */
  113.     { 8, 4, 1, 1, 2, 6 },     /* 36 */
  114.     { 7, 4, 2, 2, 3, 6 },     /* 37 */
  115.     { 6, 4, 3, 3, 4, 6 },     /* 38 */
  116.     { 5, 4, 4, 4, 5, 6 },     /* 39 */
  117.     { 4, 4, 4, 5, 6, 5 },     /* 40 */
  118.     { 3, 3, 4, 6, 6, 4 },     /* 41 */
  119.     { 2, 2, 4, 7, 6, 3 },     /* 42 */
  120.     { 1, 1, 4, 8, 6, 2 },     /* 43 */
  121.     { 7, 3, 1, 1, 3, 7 },     /* 44 */
  122.     { 6, 3, 2, 2, 4, 7 },     /* 45 */
  123.     { 5, 3, 3, 3, 5, 7 },     /* 46 */
  124.     { 4, 3, 3, 4, 6, 6 },     /* 47 */
  125.     { 3, 3, 3, 5, 7, 5 },     /* 48 */
  126.     { 2, 2, 3, 6, 7, 4 },     /* 49 */
  127.     { 1, 1, 3, 7, 7, 3 },     /* 50 */
  128.     { 6, 2, 1, 1, 4, 8 },     /* 51 */
  129.     { 5, 2, 2, 2, 5, 8 },     /* 52 */
  130.     { 4, 2, 2, 3, 6, 7 },     /* 53 */
  131.     { 3, 2, 2, 4, 7, 6 },     /* 54 */
  132.     { 2, 2, 2, 5, 8, 5 },     /* 55 */
  133.     { 1, 1, 2, 6, 8, 4 },     /* 56 */
  134.     { 5, 1, 1, 1, 5, 9 },     /* 57 */
  135.     { 4, 1, 1, 2, 6, 8 },     /* 58 */
  136.     { 3, 1, 1, 3, 7, 7 },     /* 59 */
  137.     { 2, 1, 1, 4, 8, 6 },     /* 60 */
  138.     { 1, 1, 1, 5, 9, 5 }     /* 61 */
  139. };
  140.  
  141.  
  142.  
  143. //    InitRules MUST be called before the following two tables can be used.
  144.  
  145. Boolean        _neighbours        [kFields+1] [kFields+1];
  146. Arrow        _direction        [kFields+1] [kFields+1];
  147.  
  148.  
  149.  
  150. void
  151. InitRules (void)
  152. {
  153.     Field f1, f2;
  154.     short d;
  155.     
  156.     for (f1 = 0; f1 <= kFields; f1++)
  157.     {
  158.         for (f2 = 0; f2 <= kFields; f2++)
  159.         {
  160.             _neighbours[f1][f2] = false;
  161.             _direction[f1][f2] = down;
  162.             
  163.             for (d = right; d < down; d++)
  164.             {
  165.                 if (Neighbour (f1, d) == f2)
  166.                 {
  167.                     _neighbours[f1][f2] = true;
  168.                     _direction[f1][f2] = d;
  169.                 }
  170.             }
  171.         }
  172.     }
  173. }
  174.  
  175.  
  176.  
  177. short
  178. BallsWon (BoardPtr board, short player)
  179. {
  180.     return board->loot[player-1][0];
  181. }
  182.  
  183.  
  184.  
  185. void
  186. ResetBoard (BoardPtr b)
  187. {
  188.     short f, p, q;
  189.     
  190.     for (p = 0; p < kPlayers; p++)
  191.         for (q = 0; q <= kVictory; q++)
  192.             b->loot[p][q] = 0;
  193.     
  194.     switch (gTheGame.Players)
  195.     {
  196.         default:
  197.         case 2:
  198.             for (f = 1; f <= 61; f++)
  199.             {
  200.                 b->field[f] = empty;
  201.                 
  202.                 if (f <= 16 && f != 12 && f != 13)
  203.                     b->field[f] = blak;
  204.                 else if (f >= 46 && f != 49 && f != 50)
  205.                     b->field[f] = whit;
  206.             }
  207.         break;
  208.         case 3:
  209.             for (f = 1; f <= 61; f++)
  210.             {
  211.                 b->field[f] = empty;
  212.                 
  213.                 if (Distance (f, topleft) <= 2 && Distance (f, topright) <= 2)
  214.                     b->field[f] = grin;
  215.                 else if (Distance (f, right) <= 2 && Distance (f, botright) <= 2)
  216.                     b->field[f] = blak;
  217.                 else if (Distance (f, botleft) <= 2 && Distance (f, left) <= 2)
  218.                     b->field[f] = whit;
  219.             }
  220.         break;
  221.     }
  222. }
  223.  
  224.  
  225.  
  226. Field
  227. LocToField (short h, short v)
  228. {
  229.     short    r;
  230.  
  231.     if (h < 0 || v < 0)
  232.         return 0;
  233.     
  234.     switch (v / gSet.FieldHeight)
  235.     {
  236.         case 0:            
  237.             if ((r = h / gSet.FieldWidth) < 2 || r > 6)
  238.                 return 0;
  239.             return r + 1 - 2;            
  240.         case 1:
  241.             if ((r = (h + (gSet.FieldWidth >> 1)) / gSet.FieldWidth) < 2 || r > 7)
  242.                 return 0;
  243.             return r + 6 - 2;            
  244.         case 2:
  245.             if ((r = h / gSet.FieldWidth) < 1 || r > 7)
  246.                 return 0;
  247.             return r + 12 - 1;        
  248.         case 3:
  249.             if ((r = (h + (gSet.FieldWidth >> 1)) / gSet.FieldWidth) < 1 || r > 8)
  250.                 return 0;
  251.             return r + 19 - 1;            
  252.         case 4:
  253.             if ((r = h / gSet.FieldWidth) < 0 || r > 8)
  254.                 return 0;
  255.             return r + 27 - 0;        
  256.         case 5:
  257.             if ((r = (h + (gSet.FieldWidth >> 1)) / gSet.FieldWidth) < 1 || r > 8)
  258.                 return 0;
  259.             return r + 36 - 1;        
  260.         case 6:
  261.             if ((r = h / gSet.FieldWidth) < 1 || r > 7)
  262.                 return 0;
  263.             return r + 44 - 1;        
  264.         case 7:
  265.             if ((r = (h + (gSet.FieldWidth >> 1)) / gSet.FieldWidth) < 2 || r > 7)
  266.                 return 0;
  267.             return r + 51 - 2;        
  268.         case 8:
  269.             if ((r = h / gSet.FieldWidth) < 2 || r > 6)
  270.                 return 0;
  271.             return r + 57 - 2;        
  272.         default:
  273.             return 0;
  274.     }
  275. }
  276.  
  277.  
  278.  
  279. short
  280. DoMove (BoardPtr board, MovePtr move)
  281. {
  282.     short player = board->field[move[0]] - 1;
  283.     short victim = DoPropMove (board, move[0], move[3]);
  284.     
  285.     if (victim != empty)
  286.     {
  287.         board->loot[player][0]++;
  288.         board->loot[player][board->loot[player][0]] = victim;
  289.         
  290.         return ball_down;
  291.     }
  292.     return normal_move;
  293. }
  294.  
  295.  
  296.  
  297. //    returns the id of the player whose ball is pushed off, or empty if none is pushed off
  298.  
  299. short
  300. DoPropMove (BoardPtr board, Field f, Arrow direction)
  301. {
  302.     Field    toField;
  303.     short    moveResult;
  304.  
  305.     if (board->field[f] == empty)                            //    stopcondition 1: empty field
  306.         return empty;
  307.  
  308.     toField = Neighbour (f, direction);
  309.     moveResult = DoPropMove (board, toField, direction);    //    recursive call
  310.     if (toField)
  311.         board->field[toField] = board->field[f];
  312.     else
  313.         return board->field[f];                                //    stopcondition 2: ball over the edge        
  314.         
  315.     board->field[f] = empty;
  316.     
  317.     return moveResult;
  318. }
  319.  
  320.  
  321.  
  322. short
  323. DoFlicheMove (BoardPtr board, MovePtr move)
  324. {
  325. #    define DOMOVE(F,D)    board->field [Neighbour (F, D)] = board->field [F], board->field [F] = empty
  326.  
  327.     DOMOVE (move[0], move[3]);
  328.  
  329.     DOMOVE (move[1], move[3]);
  330.         
  331.     if (move[2])
  332.         DOMOVE (move[2], move[3]);
  333.     
  334.     return normal_move;
  335. }
  336.  
  337.  
  338.  
  339. Boolean
  340. ValidMove (BoardPtr board, MovePtr move)
  341. {
  342.     short pro, contra, player = board->field[*move];
  343.     short f, direction = move[3];
  344.     
  345.     if (player == empty || ! Neighbour (*move, direction) || direction == down)
  346.         return false;
  347.     
  348.     for (    f = *move, pro = 1;
  349.             board->field[Neighbour (f, direction)] == player;
  350.             f = Neighbour (f, direction)
  351.         )
  352.         pro++;
  353.     
  354.     f = Neighbour (f, direction);
  355.     
  356.     if (board->field[f] == empty)
  357.         return pro <= 3 && f != 0;
  358.  
  359.     for (    contra = 1;
  360.             board->field[Neighbour (f, direction)] != empty
  361.         &&    board->field[Neighbour (f, direction)] != player;
  362.             f = Neighbour (f, direction)
  363.         )
  364.         contra++;
  365.     
  366.     f = Neighbour (f, direction);
  367.  
  368.     return pro <= 3 && pro > contra && board->field[f] == empty;
  369. }
  370.  
  371.  
  372.  
  373. //    This function calls ValidFlicheSorted with a sorted local copy of the fields,
  374. //    so the ordering of the balls is unchanged.
  375. //    This splitting of ValidFliche in two functions makes calling it
  376. //    more efficient in case it is known in advance the balls ARE sort3 ordered,
  377. //    which is the case for fields generated by the computer players.
  378. //    This function can be used for fliches generated by human players,
  379. //    since these are not necessarily sorted */
  380.  
  381. Boolean
  382. ValidFliche (BoardPtr board, FieldsPtr f)
  383. {
  384.     Field sf[4];
  385.     
  386.     * ((long *) (& sf)) = *((long *) f);
  387.     
  388. //    Use a sorted ball selection, with 0 (empty) at the end.
  389.     
  390.     sort3 (sf);
  391.     
  392.     return ValidFlicheSorted (board, sf);    
  393. }
  394.  
  395.  
  396.  
  397. Boolean
  398. ValidFlicheSorted (BoardPtr board, FieldsPtr sf)
  399. {
  400. //    Precondition: the fields should be ordered, with 0 (empty) at the end.
  401.     
  402.     if    (    sf[1] && board->field[sf[0]] != board->field[sf[1]]
  403.         ||    sf[2] && board->field[sf[0]] != board->field[sf[2]]
  404.         )
  405.             return false;
  406.  
  407.     if    (    (sf[1] && ! Neighbours (sf[0], sf[1]))
  408.         ||    (sf[2] && ! Neighbours (sf[1], sf[2]))
  409.         )
  410.             return false;
  411.     
  412.     if (sf[2] && (Direction (sf[0], sf[1]) != Direction (sf[1], sf[2])))
  413.         return false;
  414.  
  415.     return true;
  416. }
  417.  
  418.  
  419.  
  420. //    Same as for ValidFliche: create a local copy to sort, and call ValidFlicheMoveSorted.
  421.  
  422. Boolean
  423. ValidFlicheMove (BoardPtr board, MovePtr move)
  424. {
  425.     MoveData sf;
  426.     
  427.     * ((long *) (& sf)) = *((long *) move);
  428.     
  429.     sort3 (sf);
  430.     return ValidFlicheSorted (board, sf) && ValidFlicheMoveSorted (board, sf);
  431. }
  432.  
  433.  
  434.  
  435. Boolean
  436. ValidFlicheMoveSorted (BoardPtr board, MovePtr move)
  437. {
  438.     short moveDirection = move[3];
  439.  
  440. //    Precondition: the fields should be ordered, with 0 (empty) fields at the end.
  441. //    Precondition: the fliche should be valid.
  442.     
  443.     if (! ValidFlicheSorted (board, (FieldsPtr) move))
  444.         return false;
  445.     
  446. //    Test for moving to an occupied field.
  447.     
  448.     if    (    (             board->field[Neighbour (move[0], moveDirection)] != empty)
  449.         ||    (move[1] && board->field[Neighbour (move[1], moveDirection)] != empty)
  450.         ||    (move[2] && board->field[Neighbour (move[2], moveDirection)] != empty)
  451.         )
  452.             return false;
  453.     
  454. //    Test for suicide.
  455.     
  456.     if    (                ! Neighbour (move[0], moveDirection)
  457.         ||    move[1] &&    ! Neighbour (move[1], moveDirection)
  458.         ||    move[2] &&    ! Neighbour (move[2], moveDirection)
  459.         )
  460.             return false;
  461.             
  462. //    Test for straightness.
  463.  
  464.     if    (    move[1] && Direction (move[0], move[1]) == moveDirection
  465.         ||    move[1] && Direction (move[0], move[1]) == moveDirection - 3)
  466.             return false;        
  467.  
  468.     return true;
  469. }
  470.  
  471.  
  472.  
  473. //    Sort an array of 3 fields from low to high, but counting zeroes as highest
  474.  
  475. void
  476. sort3 (FieldsPtr fields)
  477. {
  478.     Field tmp;
  479.     
  480. #    define SWAP(X,Y) (tmp = X, X = Y, Y = tmp);
  481.  
  482.     if (fields[0] == 0 || fields[0] > fields[1] && fields[1] != 0) SWAP (fields[0], fields[1]);
  483.     if (fields[1] == 0 || fields[1] > fields[2] && fields[2] != 0) SWAP (fields[1], fields[2]);
  484.     if (fields[0] == 0 || fields[0] > fields[1] && fields[1] != 0) SWAP (fields[0], fields[1]);
  485. }
  486.